package com.bingxue.edu.framework.job;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.bingxue.edu.common.enums.RunStatusEnum;
import com.bingxue.edu.management.system.model.entity.ScheduleJobLog;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.quartz.JobExecutionContext;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;

/**
 * @author panbo
 * @since 2024/8/27
 */
@Aspect
@Component
@Slf4j
@AllArgsConstructor
public class JobAspect {

    private final SchedulerAsyncWorker schedulerAsyncWorker;

    private static final int MAX_LENGTH = 500;

    /**
     * 切面
     */
    @Pointcut("execution(void *.execute*(org.quartz.JobExecutionContext))")
    public void pointCut() {
    }

    /**
     * 定时任务日志处理
     *
     * @param joinPoint
     */
    @Around(value = "pointCut()")
    public void afterHandler(ProceedingJoinPoint joinPoint) {
        ScheduleJobLog jobLog = new ScheduleJobLog();
        jobLog.setJobId(((JobExecutionContext) joinPoint.getArgs()[0]).getJobDetail().getKey().getName());
        try {
            jobLog.setStartTime(LocalDateTime.now());
            joinPoint.proceed(joinPoint.getArgs());
            jobLog.setEndTime(LocalDateTime.now());
            Duration duration = Duration.between(jobLog.getStartTime(), jobLog.getEndTime());
            jobLog.setElapsedSeconds((int) duration.getSeconds());
            jobLog.setRunStatus(RunStatusEnum.SUCCESS);
            jobLog.setResultMessage("执行成功");
        } catch (Throwable throwable) {
            log.error("定时任务执行异常", throwable);
            // 处理异常返回结果
            String errorMsg = throwable.toString();
            StackTraceElement[] stackTraceElements = throwable.getStackTrace();
            if (ArrayUtil.isNotEmpty(stackTraceElements)) {
                errorMsg += " : " + stackTraceElements[0].toString();
            }
            errorMsg = StrUtil.sub(errorMsg, 0, MAX_LENGTH);

            jobLog.setEndTime(LocalDateTime.now());
            Duration duration = Duration.between(jobLog.getStartTime(), jobLog.getEndTime());
            jobLog.setElapsedSeconds((int) duration.getSeconds());
            jobLog.setRunStatus(RunStatusEnum.FAILED);
            jobLog.setResultMessage(errorMsg);
        }
        // 异步保存日志
        schedulerAsyncWorker.saveScheduleJobLog(jobLog);
    }

}

